
#ifndef SDCARD_H_
#define SDCARD_H_

#include "RP6M256Lib.h" 					// The RP6 M256 Library.
// Always needs to be included!

#include "sdc/fat.h"
#include "sdc/fat_config.h"
#include "sdc/partition.h"

#include "sdc/sd-reader_config.h"
#include "sdc/sd_raw.h"


struct partition_struct* partition;
struct fat_fs_struct* fs;
struct fat_file_struct* fd;
struct fat_dir_struct* dd;



/**
 * Print out some info about the SD Card (size, manufacturer etc. )
 */
uint8_t print_disk_info(const struct fat_fs_struct* fs)
{
    if(!fs)
        return 0;

    struct sd_raw_info disk_info;
    if(!sd_raw_get_info(&disk_info))
        return 0;

    writeString_P_WIFI("manuf:  0x"); 	writeInteger_WIFI(disk_info.manufacturer,HEX); writeChar_WIFI('\n');
    writeString_P_WIFI("oem:    "); 	writeString_WIFI((char*) disk_info.oem); writeChar_WIFI('\n');
    writeString_P_WIFI("prod:   "); 	writeString_WIFI((char*) disk_info.product); writeChar_WIFI('\n');
    writeString_P_WIFI("rev:    "); 	writeInteger_WIFI(disk_info.revision,DEC); writeChar_WIFI('\n');
    writeString_P_WIFI("serial: 0x"); 	writeInteger_WIFI(disk_info.serial, HEX); writeChar_WIFI('\n');
    writeString_P_WIFI("date:   "); 	writeInteger_WIFI(disk_info.manufacturing_month, DEC); writeChar_WIFI('/');
										writeInteger_WIFI(disk_info.manufacturing_year, DEC); writeChar_WIFI('\n');
    writeString_P_WIFI("size:   "); 	writeInteger_WIFI(disk_info.capacity / 1024 / 1024, DEC);  writeString_P_WIFI("MB\n");
    writeString_P_WIFI("copy:   "); 	writeInteger_WIFI(disk_info.flag_copy,DEC); writeChar_WIFI('\n');
    writeString_P_WIFI("wr.pr.: "); 	writeInteger_WIFI(disk_info.flag_write_protect_temp,DEC); writeChar_WIFI('/');
										writeInteger_WIFI(disk_info.flag_write_protect,DEC); writeChar_WIFI('\n');
    writeString_P_WIFI("format: "); 	writeInteger_WIFI(disk_info.format,DEC); writeChar_WIFI('\n');
  
    writeString_P_WIFI("free:   "); 	writeInteger_WIFI(fat_get_fs_free(fs),DEC); writeChar_WIFI('/');
										writeInteger_WIFI(fat_get_fs_size(fs),DEC); writeChar_WIFI('\n');
	
    return 1;
}


/**
 * Finds a specific file in a directory.
 */
uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
{
    while(fat_read_dir(dd, dir_entry))
    {
        if(strcmp(dir_entry->long_name, name) == 0)
        {
            fat_reset_dir(dd);
            return 1;
        }
    }

    return 0;
}

/**
 * Opens a file in a directory
 */
struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
{
    struct fat_dir_entry_struct file_entry;
    if(!find_file_in_dir(fs, dd, name, &file_entry))
        return 0;

    return fat_open_file(fs, &file_entry);
}

uint8_t openDirectory(char *name){
	// open root directory
	struct fat_dir_entry_struct directory;
	fat_get_dir_entry_of_path(fs, name, &directory);

	dd = fat_open_dir(fs, &directory);
	if(dd)
	{
		writeString_P_WIFI("opening root directory OK!\n");

	}
	else {
		writeString_P_WIFI("opening root directory failed!\n");
		writeString_P_WIFI("Please verify that the SD Card is OK!\n");
		return false;
	}
	return true;
}	


void testsdcard(void){
	writeString_P_WIFI("Testing SD Card. Please wait (SDHC Cards will take longer)...\n\n");
	
	if(sd_raw_init())
	{
		writeString_WIFI("SD INIT OK!\n");
	}
	else
	{
		writeString_WIFI("SD INIT FAILED!\n");
		writeString_P_WIFI("Please verify that the SD Card is OK and properly inserted!\n");
		return;
	}
	
	
	mSleep(100);
	setLEDs(0b0000);

	// open first partition
	struct partition_struct* partition =
	partition_open(
	sd_raw_read,
	sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
	sd_raw_write,
	sd_raw_write_interval,
	#else
	0,
	0,
	#endif
	0
	);


	if(!partition)
	{
		// If the partition did not open, assume the storage device
		// is a "superfloppy", i.e. has no MBR.
		partition = partition_open(sd_raw_read,
		sd_raw_read_interval,
		#if SD_RAW_WRITE_SUPPORT
		sd_raw_write,
		sd_raw_write_interval,
		#else
		0,
		0,
		#endif
		-1
		);
		if(partition)
		{
			writeString_P_WIFI("Opening partition OK!\n");
		}
		else {
			writeString_P_WIFI("Opening partition FAILED!\n");
			writeString_P_WIFI("Please verify that the SD Card is OK!\n");
			return;
		}
	}


	// open file system
	struct fat_fs_struct* fs = fat_open(partition);
	if(fs)
	{
		writeString_P_WIFI("opening filesystem OK!\n");
	}
	else {
		writeString_P_WIFI("opening filesystem failed!\n");
		writeString_P_WIFI("Please verify that the SD Card is OK!\n");
		return;
	}

	
	// open root directory
	struct fat_dir_entry_struct directory;
	fat_get_dir_entry_of_path(fs, "/", &directory);

	struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
	if(dd)
	{
		writeString_P_WIFI("opening root directory OK!\n");

	}
	else {
		writeString_P_WIFI("opening root directory failed!\n");
		writeString_P_WIFI("Please verify that the SD Card is OK!\n");
		return;
	}

	// print some card information
	print_disk_info(fs);
	
	// print directory listing
	struct fat_dir_entry_struct dir_entry;
	while(fat_read_dir(dd, &dir_entry))
	{
		uint8_t spaces = sizeof(dir_entry.long_name) - strlen(dir_entry.long_name) + 4;

		writeString_WIFI(dir_entry.long_name);
		writeChar_WIFI(dir_entry.attributes & FAT_ATTRIB_DIR ? '/' : ' ');
		while(spaces--)
		writeChar_WIFI(' ');
		writeInteger_WIFI(dir_entry.file_size,DEC);
		writeChar_WIFI('\n');
	}
	
	writeString_P_WIFI("\n\n");
	
	  fat_close_dir(dd);
	  fat_close(fs);
	  partition_close(partition);
}

#endif /* SDCARD_H_ */